﻿using UnityEngine;
using System;
using System.Collections;

namespace Hont.HyperWigglePackage
{
    public class HyperWiggle
    {
        bool mIsExecute;
        float mFPS = 0f;
        float mBeginTimeStamp;

        PRPair mLast;
        Action mOnFinished;
        PRPair[] mWiggleData;
        Action<PRPair> mSetTargetFunc;


        public void Start(Transform target, IHyperWiggleData wiggleData, Action onFinished)
        {
            Start((pr) =>
            {
                target.position += pr.RelativePosition;
                target.eulerAngles += pr.RelativeRotation;
            }, wiggleData, onFinished);
        }

        public void Start(Action<PRPair> setTarget, IHyperWiggleData wiggleData, Action onFinished)
        {
            mOnFinished = onFinished;

            mSetTargetFunc = setTarget;
            mWiggleData = wiggleData.GetData();
            mFPS = wiggleData.FPS;
            mBeginTimeStamp = Time.time;
            mLast = default(PRPair);

            mIsExecute = true;
        }

        /// <summary>
        /// Please put to 'Update' invoke.
        /// </summary>
        public void Update()
        {
            if (!mIsExecute) return;

            var frameTime = 1 / mFPS;
            var timeDiff = Time.time - mBeginTimeStamp;
            var frame = Mathf.Min(mWiggleData.Length - 1, Mathf.FloorToInt(timeDiff / frameTime));

            var position = Vector3.zero;
            var rotation = Vector3.zero;

            if (frame + 1 < mWiggleData.Length)
            {
                var t = (timeDiff - frame * frameTime) / frameTime;

                var currentPosition = Vector3.Lerp(mWiggleData[frame].AbsolutePosition, mWiggleData[frame + 1].AbsolutePosition, t);
                var currentRotation = Vector3.Lerp(mWiggleData[frame].AbsoluteRotation, mWiggleData[frame + 1].AbsoluteRotation, t);
                position = currentPosition - mLast.AbsolutePosition;
                rotation = currentRotation - mLast.AbsoluteRotation;

                mLast.AbsolutePosition = currentPosition;
                mLast.AbsoluteRotation = currentRotation;
            }
            else
            {
                position = mWiggleData[frame].AbsolutePosition - mLast.AbsolutePosition;
                rotation = mWiggleData[frame].AbsoluteRotation - mLast.AbsoluteRotation;
            }

            mSetTargetFunc(new PRPair() { RelativePosition = position, RelativeRotation = rotation });

            if (frame + 1 == mWiggleData.Length)
            {
                if (mOnFinished != null) mOnFinished();
                mIsExecute = false;
            }
        }
    }
}
